package ro.romanescu.useradmin.hibernate;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;


/**
 * Access to hibernate functionality. Logical operation is to openSession(),
 * do operations and then closeSession() when all is finished or an error
 * occurred.
 */
public final class HibernateDS
{
  private static final Logger log = LogManager.getLogger( HibernateDS.class );

  private static SessionFactory dbSessionFactory = null;

  private static final ThreadLocal<Session> dbSession = new ThreadLocal<Session>();

  /**
   * Open new hibernate session for database operations.
   * @return Session object
   * @throws HibernateException If hibernate cannot open new session
   */
  public static Session openSession() throws HibernateException
  {
    Session session = dbSession.get();
    if( session == null )
    {
      if( dbSessionFactory == null )
      {
        log.debug( "Creating session factory for database schema" );
        Configuration cfg = new Configuration();
        cfg.configure( "hibernate.cfg.xml" );
        dbSessionFactory = cfg.buildSessionFactory();
      }
      session = dbSessionFactory.openSession();
      dbSession.set( session );
    }
    return session;
  }


  /**
   * Close the hibernate session associated with DSS schema. This method must be called after finishing
   * working with the session. Normal operations is:
   * <code>
   *  ...
   *  Session s = HibernateDS.openSession();
   *  ...
   *  do stuff with the session.
   *  ...
   *  HibernateDS.closeSession();
   * </code>
   * <em>
   *  WARNING! Do not close the Session object explicitly! Session must be
   *  closed ONLY with this method. The reason behind is that each Session is
   *  assigned to a ThreadLocal variable. Explicitly closing the session means
   *  that the thread local variable remains initialized, but with a session
   *  in a closed state, disabling further operations.
   * </em>
   */
  public static void closeSession()
  {
    Session session = dbSession.get();
    if( session != null )
    {
      try
      {
        session.close();
      }
      catch( HibernateException ex )
      {
        log.error( "closeDSS(): Error closing hibernate session", ex );
      }
    }
    dbSession.set( null );
  }
}
